package org.simpleframework.inject;

import java.lang.reflect.Field;
import java.util.Set;
import lombok.extern.slf4j.Slf4j;
import org.simpleframework.core.BeanContainer;
import org.simpleframework.inject.annotation.Autowried;
import org.simpleframework.util.ClassUtil;
import org.simpleframework.util.ValidationUtil;

/**
 * @Author: yu.zhou
 * @DateTime: 2023/01/05 14:50
 */
@Slf4j
public class DependencyInjector {

    /**
     * IOC容器作为私有成员变量
     */
    private BeanContainer beanContainer;

    /**
     * ioc容器的实例化
     */
    public DependencyInjector() {
        beanContainer = BeanContainer.getInstance();
    }

    public void doIOC() {
        Set<Class<?>> classes = beanContainer.getClasses();
        if (ValidationUtil.isEmpty(classes)) {
            log.warn("empty class set in beanContainer");
            return;
        }
        // 1.遍历ioc容器的字节码对象
        for (Class<?> clazz : classes) {
            // 2.遍历字节码对象的所有成员变量
            Field[] declaredFields = clazz.getDeclaredFields();
            if (ValidationUtil.isEmpty(declaredFields)) {
                continue;
            }
            for (Field field : declaredFields) {
                // 3.找出被@Autowried标注的成员变量
                if (field.isAnnotationPresent(Autowried.class)) {
                    Autowried autowried = field.getAnnotation(Autowried.class);
                    String beanName = autowried.value();
                    // 4. 获取成员变量的类型
                    Class<?> fieldType = field.getType();
                    // 5.通过类型获取容器中对应的实例
                    Object fieldInstance = getFieldInstance(fieldType, beanName);
                    if (fieldInstance == null) {
                        throw new RuntimeException(
                                "unable to inject relevant type,target filedClass is :" + fieldType.getName());
                    } else {
                        // 6.利用反射注入到成员变量中
                        Object targetBean = beanContainer.getBean(clazz);
                        ClassUtil.setFiled(targetBean, field, fieldInstance, true);

                    }

                }
            }
        }
    }

    /**
     * 根据class在beanContain里获取它的实例或者实现类
     *
     * @param fieldClass 变量类型
     * @param beanName
     * @return
     */
    private Object getFieldInstance(Class<?> fieldClass, String beanName) {
        Object fieldValue = beanContainer.getBean(fieldClass);
        if (fieldValue != null) {
            return fieldValue;
        } else {
            Class<?> implementClass = getImplementClass(fieldClass, beanName);
            if (implementClass != null) {
                return beanContainer.getBean(implementClass);
            } else {
                return null;
            }
        }
    }

    /**
     * 获取接口对应的实现类
     *
     * @param fieldClass
     * @param beanName
     * @return
     */
    private Class<?> getImplementClass(Class<?> fieldClass, String beanName) {
        // 获取ioc容器中父接口的所有实现类的class集合
        Set<Class<?>> classSet = beanContainer.getClassBySuper(fieldClass);
        if (ValidationUtil.isEmpty(classSet)) {
            return null;
        }
        // 如果beanName为空证明用户没有设置value值,此时要么抛出异常,正常返回
        if (ValidationUtil.isEmpty(beanName)) {
            // 如果默认class集合中只有一个元素就直接返回,否则就抛出异常
            if (classSet.size() == 1) {
                return classSet.iterator().next();
            } else {
                throw new RuntimeException("multiple implemented classes for" + fieldClass.getName()
                        + "please set Autowired value to pick one");
            }
        }
        // 如果beanName不为空就需要遍历满足接口类型的所有实现类
        for (Class<?> clazz : classSet) {
            if (beanName.equals(clazz.getSimpleName())) {
                return clazz;
            }
        }
        return null;
    }
}
